// Copyright Leonid Shlyapnikov 2011
// Distributed under the GNU Lesser General Public License http://www.gnu.org/licenses/lgpl.html
//    author: Leonid Shlyapnikov, created on: Jun 11, 2011

#ifndef FIXPARSER_CPP_SRC_MAIN_FIXPARSER_DEFINE_MSG_MACRO_H_
#define FIXPARSER_CPP_SRC_MAIN_FIXPARSER_DEFINE_MSG_MACRO_H_

#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/size.hpp>

#include <limits>

// This macro should not be used directly, indented to be used by FIXPARSER_DEFINE_TAG_TO_INDEX
// the number of parameters and order is dictated by BOOST_PP_SEQ_FOR_EACH_I
#define FIXPARSER_TAG_TO_INDEX_CASE_(r, data, i, elem)                              \
    case elem: return (i + data);                                                   \
    /**/

// This macro defines the switch-case statement to convert incoming tagNumber into an array index with
// base starting from baseIndex, tagSeq - specifies sequence of tags participating in the convertion
// see tag_to_index_macro_test.cpp for some examples.
#define FIXPARSER_DEFINE_TAG_TO_INDEX(tagNumber, baseIndex, tagSeq)                 \
    switch (tagNumber) {                                                            \
    BOOST_PP_SEQ_FOR_EACH_I(FIXPARSER_TAG_TO_INDEX_CASE_, baseIndex, tagSeq)        \
    default:                                                                        \
        return std::numeric_limits<size_t>::max();                                  \
    }                                                                               \
    /**/

// TODO(shl) remove invalidIndex() method
#define FIXPARSER_DEFINE_MSG(msgClassName, msgType, tagSeq)                                 \
    struct msgClassName {                                                                   \
        static size_t tagToIndex(size_t tagNumber) {                                        \
            switch (tagNumber) {                                                            \
            BOOST_PP_SEQ_FOR_EACH_I(FIXPARSER_TAG_TO_INDEX_CASE_, 0, tagSeq)                \
            default:                                                                        \
                return invalidIndex();                                                      \
            }                                                                               \
        }                                                                                   \
                                                                                            \
        static size_t numberOfIndexedTags() {                                               \
            return BOOST_PP_SEQ_SIZE(tagSeq);                                               \
        }                                                                                   \
                                                                                            \
        static const char* type() {                                                         \
            return msgType;                                                                 \
        }                                                                                   \
                                                                                            \
        static bool isInvalidIndex(size_t index) {                                          \
            return std::numeric_limits<size_t>::max() == index;                             \
        }                                                                                   \
                                                                                            \
        static size_t invalidIndex() {                                                      \
            return std::numeric_limits<size_t>::max();                                      \
        }                                                                                   \
                                                                                            \
        static const size_t NUMBER_OF_INDEXED_TAGS = BOOST_PP_SEQ_SIZE(tagSeq);             \
                                                                                            \
    }                                                                                       \
    /**/

#endif  // FIXPARSER_CPP_SRC_MAIN_FIXPARSER_DEFINE_MSG_MACRO_H_
